Below is the specification for the Custom Control support
in the Dialog Editor (DlgEdit.Exe) for Windows NT.

There are several reasons why the existing Windows 3.x scheme is not
adequate for NT:

1. DlgEdit can easily be crashed by a user.  The way that a custom
   control DLL is written for Win 3.x, it must export three functions at
   three hard-coded ordinals (2, 3 and 4).  The user chooses a menu
   option that invokes a file open dialog, enters the name of a DLL then
   presses OK to ask the Dialog Editor to load this "custom control DLL".
   The editor loads the specified module, checks for and gets the address
   of these ordinals, pushes parms on the stack, and starts calling
   them.  There is no way for it to validate that the DLL that the
   user chose is really a custom control DLL.  It checks for the
   existence of these three ordinals, but because most DLL's will
   have at least four exports, and usually start at 1, this doesn't
   help much.  This means that a user can easily crash the editor
   by trying to load a random DLL, such as USERSRV.DLL.

2. There is no allowance for UNICODE.  The current scheme of exporting
   ordinals does not allow for an xxxA and xxxW version of the api's.
   Also, a set of xxxW structures need to be defined with room for the
   UNICODE strings.

3. The structures passed around have obsolete fields, and some are not
   dword aligned.  This interface was originally written for the Win 3.0
   dialog editor (dialog.exe) and some fields are not necessary for
   the Win 3.1 and NT dialog editor (DlgEdit.Exe).

4. There is no support for some of the new features of the Win 32
   resource file format, such as Extended Styles for controls and
   NLS Language and Sub-Language values.

5. There is no support for some of the features of the new Dialog
   Editor, such as sizing to text, or specifying that the control
   does not take text and allowing the editor to disable the Text
   entry field on the Properties Bar to prevent text from being
   entered for the control.

6. Custom controls are limited to one class per DLL.  This is an
   arbitrary restriction based on the structures used, and groups
   like Pen Windows have had to use hacks to work around this.


The real driving factor is #2 above, the lack of support for UNICODE.
Because of these reasons, the following will be the support of
Custom Controls in the Win32 (NT) Dialog Editor.  For more information,
look at the CUSTCNTL.H header file.


-- INITIALIZING A CUSTOM CONTROL ----------------------------------------

Custom control DLL's should export one or both of the following
functions by name (the ordinal used for the export does not matter):

UINT CALLBACK CustomControlInfoA(LPCCINFOA acci)
UINT CALLBACK CustomControlInfoW(LPCCINFOW acci)

The parameter to these functions is either NULL, or a pointer to an
array of CCINFOA or CCINFOW  structures, defined as follows:

typedef struct tagCCINFOA {
    CHAR    szClass[CCHCCCLASS];     // Class name for the control.
    DWORD   flOptions;               // Option flags (CCF_* defines).
    CHAR    szDesc[CCHCCDESC];       // Short, descriptive text for the ctrl.
    UINT    cxDefault;               // Default width (in dialog units).
    UINT    cyDefault;               // Default height (in dialog units).
    DWORD   flStyleDefault;          // Default style (WS_CHILD | WS_VISIBLE).
    DWORD   flExtStyleDefault;       // Default extended style.
    DWORD   flCtrlTypeMask;          // Mask for control type styles.
    CHAR    szTextDefault[CCHCCTEXT];// Default text.
    INT     cStyleFlags;             // Entries in the following style table.
    LPCCSTYLEFLAGA aStyleFlags;      // Points to style flag table.
    LPFNCCSTYLEA lpfnStyle;          // Pointer to the Styles function.
    LPFNCCSIZETOTEXTA lpfnSizeToText;// Pointer to the SizeToText function.
    DWORD   dwReserved1;             // Reserved.  Must be zero.
    DWORD   dwReserved2;             // Reserved.  Must be zero.
} CCINFOA, *LPCCINFOA;

typedef struct tagCCINFOW {
    WCHAR   szClass[CCHCCCLASS];     // Class name for the control.
    DWORD   flOptions;               // Option flags (CCF_* defines).
    WCHAR   szDesc[CCHCCDESC];       // Short, descriptive text for the ctrl.
    UINT    cxDefault;               // Default width (in dialog units).
    UINT    cyDefault;               // Default height (in dialog units).
    DWORD   flStyleDefault;          // Default style (WS_CHILD | WS_VISIBLE).
    DWORD   flExtStyleDefault;       // Default extended style.
    DWORD   flCtrlTypeMask;          // Mask for control type styles.
    INT     cStyleFlags;             // Entries in the following style table.
    LPCCSTYLEFLAGW aStyleFlags;      // Points to style flag table.
    WCHAR   szTextDefault[CCHCCTEXT];// Default text.
    LPFNCCSTYLEW lpfnStyle;          // Pointer to the Styles function.
    LPFNCCSIZETOTEXTW lpfnSizeToText;// Pointer to the SizeToText function.
    DWORD   dwReserved1;             // Reserved.  Must be zero.
    DWORD   dwReserved2;             // Reserved.  Must be zero.
} CCINFOW, *LPCCINFOW;


    szClass             - Class name of the control type.  This
                          class must be registered by the DLL with
                          a RegisterClass call.

    flOptions           - Option flags, as follows:

                            CCF_NOTEXT - The control does not have text.
                                         The Text entry field in the
                                         Properties Bar of the dialog
                                         editor will not allow text to
                                         be entered for this control.

    szDesc              - A short description of the control type.  This
                          can be a zero length string.

    cxDefault           - Suggested width of new controls of this type.
                          This value is in dialog units (not pixels).

    cyDefault           - Suggested height of new controls of this type.
                          This value is in dialog units (not pixels).

    flStyleDefault      - Initial style of new controls of this type.
                          At a minimum, this should include WS_VISIBLE
                          and WS_CHILD.

    flExtStyleDefault   - Initial extended style of new controls of this type.

    flCtrlTypeMask      - A mask that identifies which bits of flStyleDefault
                          are bits that differentiate between the different
                          types of controls in this class.  This can be
                          zero if there is only one type of control
                          defined for this class.  See below for more
                          information.

    cStyleFlags         - The number of elements (styles) in the following
                          array.

    aStyleFlags         - Pointer to a LPCCSTYLEFLAGA(W) structure(s) that
                          contains style information for the control.

    szTextDefault       - Initial text of new controls of this type.  This
                          can be a zero length string for no initial text.

    lpfnStyle           - Pointer to the associated custom control Styles
                          function for this control type.  This can be
                          NULL if the custom control does not have a
                          private Styles dialog written for it.  If
                          NULL, a generic Styles dialog will be used
                          by the dialog editor when the user wants to
                          edit the styles for the control.  See below.

    lpfnSizeToText      - Pointer to the associated custom control
                          SizeToText function for this control type.
                          This can be NULL if the control cannot be
                          sized to it's text, and is ignored if CCF_NOTEXT
                          is specified for flOptions.  See below.

    dwReserved1         - Reserved value.  Must be zero.

    dwReserved2         - Reserved value.  Must be zero.


The CustomControlInfoW function will be used if it is available,
otherwise the CustomControlInfoA function will be used.  The function
must return the number of controls that the DLL supports, or
zero if an error occurs.

The CustomControlInfoA(W) function will be called with a NULL parameter
first, to obtain the number of supported controls.  It will then
be called with a pointer to an array of CCINFOA(W) structures.  The
function should fill in this array with information about each of
the control types that it supports.

Note that the lpfnStyle and lpfnSizeToText fields, if
not NULL,  will point to functions that expect UNICODE strings/structures
in the CCINFOW structure, or functions that expect ANSI strings if in
the CCINFOA structure.

The flCtrlTypeMask field specifies which bits of the flStyleDefault field
are used for defining a different "type" of control within the class.  For
instance, the standard "BUTTON" class includes several different types
of buttons, including Radio Buttons, Push Buttons, Check Boxes, etc.
These different styles of the "BUTTON" class are all distinguished by the
lower four bits of the style.  In this case, the flCtrlTypeMask would
be 0x000F.  There are other styles, such as BS_LEFTTEXT (0x0020) that
can be used with several button types, and the mask would be used to
strip this style out when looking for a match.  The mask value is used
to help the dialog editor match up a custom control from a dialog being
edited with the exact type of the custom control class from the different
control type variants that may have been defined for a class.  Because
each control type within a class can have it's own Styles and
SizeToText function specified, it can be important that a control be
matched up with the proper control type within the custom control DLL.

If the custom control DLL only has one control type for each class, or
the same Styles and SizeToText function is used for each of
the different control types within each class, then the flCtrlTypeMask
value can be zero, because it is not important that a certain control
type be matched up with the exact control type from the DLL that it
was originally created from.  In all cases, however, each control type
with the same class name must have the same mask specified.


-- CHANGING THE STYLES OF A CUSTOM CONTROL ---------------------------

When the user of DlgEdit requests that the styles for a custom control
be edited, the editor will call the function specified in the
lpfnStyle field of the CCINFOA(W) structure.  This function should be
written to bring up and process a dialog box that allows the user
to edit the styles of the custom control.  This dialog should be
designed so that it follows the general style guidelines of the existing
styles dialogs in the dialog editor.  The function has the following
prototype:

BOOL CALLBACK XxxxStyleA (HWND hwndParent,  LPCCSTYLEA pccs)

BOOL CALLBACK XxxxStyleW (HWND hwndParent,  LPCCSTYLEW pccs)

The function name 'XxxxStyleA(W)' is a placeholder for the real name
that you give the function.  The actual name does not matter.
It will be called with the following parameters:

    hwndParent      - The parent window for the dialog that will be
                      displayed.  The styles function should use
                      this window as the parent of the styles dialog
                      that it displays.

    pccs            - Points to a CCSTYLEA(W) structure.  This structure
                      contains the initial style of the control.  The
                      style should be modified based on the user's
                      input from the styles dialog.

The CCSTYLEA(W) structures are defined as follows:

typedef struct tagCCSTYLEA {
    DWORD   flStyle;                // Style of the control.
    DWORD   flExtStyle;             // Extended style of the control.
    CHAR    szText[CCHCCTEXT];      // Text of the control.
    LANGID  lgid;                   // Language Id of the control's dialog.
    WORD    wReserved1;             // Reserved value.  Do not change.
} CCSTYLEA, *LPCCSTYLEA;

typedef struct tagCCSTYLEW {
    DWORD   flStyle;                // Style of the control.
    DWORD   flExtStyle;             // Extended style of the control.
    WCHAR   szText[CCHCCTEXT];      // Text of the control.
    LANGID  lgid;                   // Language Id of the control's dialog.
    WORD    wReserved1;             // Reserved value.  Do not change.
} CCSTYLEW, *LPCCSTYLEW;

    flStyle     - Contains the current style of the control.  This
                  should be set to what the user chose before
                  returning.

    flExtStyle  - Contains the current extended style of the control.
                  This should be set to what the user chose before
                  returning.

    szText      - Contains the current text for this control.  This text
                  can be changed, although it is not recommended.
                  The Properties Bar in DlgEdit allows the text to be
                  changed, and so this functionality does not normally
                  need to be in the styles dialog for the custom control.
                  An exception might be if the text of the control
                  contains special information or control codes, and
                  is interpreted in an unusual way by the custom control.

    lgid        - Language id of the dialog the control is in.  Provided
                  for informational purposes only, and should not be
                  changed.

    wReserved1  - Reserved value.  Do not change.


This function should allow the user to change the styles for the control,
update the CCSTYLEA(W) structure with the new values, then return TRUE.
If the user cancels the dialog or an error occurs, the function should
return FALSE.

If the lpfnStyle field of the CCINFOA(W) structure is NULL, a default
Styles dialog will be used by the dialog editor.  This dialog will allow
all the bits of the style to be set, but will not have meaningful names
for them, and some bit settings may not be valid for the custom control.
It is better if the custom control provides it's own dialog.



-- SIZING TO TEXT SUPPORT -----------------------------------------------

It can be very useful for a custom control to be sized to fit it's text,
along with the other standard controls (radio buttons, push buttons, etc.)
that support this.  However, the dialog editor does not know what size of
a margin, etc. a custom control has, and cannot automatically size it to
fit the text.  The optional lpfnSizeToText field of the CCINFOA(W)
structure allows a custom control to specify a function that will be
called for the custom control when the user specifies that it should be
sized to it's text.  This function will have the following prototype:


INT CALLBACK XxxxSizeToTextA (DWORD flStyle, DWORD flExtStyle,
                              HFONT hfont,   LPSTR pszText)

INT CALLBACK XxxxSizeToTextW (DWORD flStyle, DWORD flExtStyle,
                              HFONT hfont,   LPWSTR pszText)

    flStyle     - Style of the control.  This may be necessary to
                  determine how it should be sized.

    flExtStyle  - Extended style of the control.  This may be necessary
                  to determine how it should be sized.

    hfont       - Either NULL or the font that is selected for the
                  current dialog being edited.  This font should be used
                  when determining the size of the control.  This font
                  should not be deleted or left selected in a DC when
                  the function returns.

    pszText     - The text to size the custom control to.

The XxxxSizeToTextA(W) function should use the specified styles, font and
text string to determine the minimum size of the custom control,  then should
return this value.  This value should be in pixels, not dialog units.
The function should return -1 if an error occurs.

